package com.altekis.kanbankaze.client;

import com.altekis.kanbankaze.shared.events.RPCCompletedEvent;
import com.altekis.kanbankaze.shared.events.RPCStartedEvent;
import com.google.gwt.core.client.GWT;
import com.google.gwt.http.client.RequestTimeoutException;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
import com.google.gwt.user.client.rpc.InvocationException;
import com.google.gwt.user.client.rpc.SerializationException;
/**
 * Utility class that provides retries, status feedback and centralized logical exception control to RPC service calls
 * @author lordkhizir
 *
 * @param <T>
 */
public abstract class RPCCall<T> implements AsyncCallback<T>{
	protected abstract void callService(AsyncCallback<T> cb);
	private void call(final int retriesLeft, final String message) {
		GWT.log("Calling with " + retriesLeft + " and message " + message);
		onRPCStarted(message);
		callService(new AsyncCallback<T>() {
			public void onFailure(Throwable caught) {
				onRPCCompleted();
				GWT.log(caught.toString(), caught);
				try {
					throw caught;
				} catch (InvocationException invocationException) {
//					if(caught.getMessage().equals(SharedConstants.LOGGED_OUT)){
//						ConnectrApp.get().getEventBus().fireEvent(new LogoutEvent());
//						return;
//					} TODO Control sesion
					if (retriesLeft <= 0) {
						RPCCall.this.onFailure(invocationException);
					} else {
						call(retriesLeft - 1, message); // retry call
					}
				} catch (IncompatibleRemoteServiceException remoteServiceException) {
					Window.alert("The app maybe out of date. Reload this page in your browser.");
				} catch (SerializationException serializationException) {
					Window.alert("A serialization error occurred. Try again.");
				
//				} catch (NotLoggedInException e) {
//					ConnectrApp.get().getEventBus().fireEvent(new LogoutEvent());
//					// TODO User not logged in. Redirect to login page
				} catch (RequestTimeoutException e) {
					Window.alert("This is taking too long, try again");
				} catch (Throwable e) {// application exception
					RPCCall.this.onFailure(e);
				}
			}
			public void onSuccess(T result) {
				onRPCCompleted();
				RPCCall.this.onSuccess(result);
			}
		});
	}
	private void onRPCCompleted() {
		Injector.INSTANCE.getEventBus().fireEvent(new RPCCompletedEvent());
	}
	private void onRPCStarted(String message) {
		Injector.INSTANCE.getEventBus().fireEvent(new RPCStartedEvent(message));
	}
	public void retry(int retryCount, String message) {
		call(retryCount, message);
	}
}
